Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ


Displaying Raw β€’ Download

scripts/verify-rb.sh 4d4070c8e1ed73a56ee2f054300a0f62e3fe2e62 (4d4070c8) Text, 5.72 KB

T8b949e#!/usr/bin/env bash
T8b949e# Reproducible-build verification for F-Droid/IzzyOnDroid.
T8b949e# https://izzyondroid.org/docs/reproducibleBuilds/DebugFailedRBs/
T8b949e# https://github.com/meshtastic/Meshtastic-Android/issues/3231
T8b949e# Run from repo root with VERSION_CODE exported (CI: rb-check).
T8b949e# No pipefail on purpose: `unzip -l | grep -q` SIGPIPEs unzip on first match.
Tffa657set -eu

T8b949e# Created BEFORE any Gradle run β€” fixed /tmp paths could be symlink-squatted by build logic.
Te6edf3WORKDIRTff7b72=Tff7b72$(mktemp -dTff7b72)
Tffa657trap Ta5d6ff'rm -rf "$WORKDIR"' EXIT

Tffa657echo Ta5d6ff"── Step 1: Verify aboutlibraries.json determinism ──"
rm -f androidApp/src/main/resources/aboutlibraries.json
./gradlew :androidApp:exportLibraryDefinitions -PciTff7b72=Tffa657true -Dorg.gradle.isolated-projectsTff7b72=Tffa657false --no-configuration-cache
cp androidApp/src/main/resources/aboutlibraries.json Ta5d6ff"Te6edf3$WORKDIRTa5d6ff/aboutlibraries-run1.jsonTa5d6ff"

rm -f androidApp/src/main/resources/aboutlibraries.json
./gradlew :androidApp:exportLibraryDefinitions -PciTff7b72=Tffa657true -Dorg.gradle.isolated-projectsTff7b72=Tffa657false --no-configuration-cache --rerun-tasks
cp androidApp/src/main/resources/aboutlibraries.json Ta5d6ff"Te6edf3$WORKDIRTa5d6ff/aboutlibraries-run2.jsonTa5d6ff"

Tff7b72if ! diff -q Ta5d6ff"Te6edf3$WORKDIRTa5d6ff/aboutlibraries-run1.jsonTa5d6ff" Ta5d6ff"Te6edf3$WORKDIRTa5d6ff/aboutlibraries-run2.jsonTa5d6ff"Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"::error::aboutlibraries.json is NOT deterministic across runs!"
diff Ta5d6ff"Te6edf3$WORKDIRTa5d6ff/aboutlibraries-run1.jsonTa5d6ff" Ta5d6ff"Te6edf3$WORKDIRTa5d6ff/aboutlibraries-run2.jsonTa5d6ff" Tb4b4b4| head -20
Tffa657exit T79c0ff1
Tff7b72fi
Tffa657echo Ta5d6ff"βœ… aboutlibraries.json is deterministic"

Tffa657echo Ta5d6ff"── Step 2: Build fdroid release APK ──"
./gradlew :androidApp:assembleFdroidRelease -PciTff7b72=Tffa657true -Pmeshtastic.disableAbiSplitsTff7b72=Tffa657true -Dorg.gradle.isolated-projectsTff7b72=Tffa657false --no-configuration-cache

Te6edf3APKTff7b72=Tff7b72$(find androidApp/build/outputs/apk/fdroid/release -name Ta5d6ff"*.apk" Tb4b4b4| head -1Tff7b72)
Tff7b72if Tff7b72[ -z Ta5d6ff"Te6edf3$APKTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"::error::No fdroid release APK found"
Tffa657exit T79c0ff1
Tff7b72fi
Tffa657echo Ta5d6ff"Ta5d6ffChecking APK: Te6edf3$APKTa5d6ff"

Tffa657echo Ta5d6ff"── Step 3: Check for datadog.buildId ──"
Tff7b72if unzip -l Ta5d6ff"Te6edf3$APKTa5d6ff" Tb4b4b4| grep -q Ta5d6ff"datadog.buildId"Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"::error::fdroid APK contains assets/datadog.buildId β€” breaks RB!"
Tffa657exit T79c0ff1
Tff7b72fi
Tffa657echo Ta5d6ff"βœ… No datadog.buildId in fdroid APK"

Tffa657echo Ta5d6ff"── Step 4: Check for proprietary libraries (dex scan) ──"
Te6edf3APK_DIRTff7b72=Ta5d6ff"Te6edf3$WORKDIRTa5d6ff/apkTa5d6ff"
mkdir Ta5d6ff"Te6edf3$APK_DIRTa5d6ff"
unzip -q Ta5d6ff"Te6edf3$APKTa5d6ff" -d Ta5d6ff"Te6edf3$APK_DIRTa5d6ff"
Te6edf3OFFENDERSTff7b72=Ta5d6ff""
Tff7b72for pattern Tff7b72in Ta5d6ff"com/google/firebase" Ta5d6ff"com/google/android/gms" Ta5d6ff"com/crashlytics" Ta5d6ff"com/google/mlkit" Ta5d6ff"com/google/android/datatransport" Ta5d6ff"androidx/privacysandbox/ads"Tb4b4b4; Tff7b72do
Tff7b72for dex Tff7b72in Ta5d6ff"Te6edf3$APK_DIRTa5d6ff"/classes*.dexTb4b4b4; Tff7b72do
Tff7b72if Tff7b72[ -f Ta5d6ff"Te6edf3$dexTa5d6ff" Tff7b72] Tff7b72&& strings Ta5d6ff"Te6edf3$dexTa5d6ff" Tb4b4b4| grep -q Ta5d6ff"Ta5d6ffLTffd700${Te6edf3patternTffd700}Ta5d6ff/Ta5d6ff"Tb4b4b4; Tff7b72then
Te6edf3OFFENDERSTff7b72=Ta5d6ff"Tffd700${Te6edf3OFFENDERSTffd700}Ta5d6ff\n - Te6edf3$patternTa5d6ff"
Tff7b72break
Tff7b72fi
Tff7b72done
Tff7b72done

Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$OFFENDERSTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo -e Ta5d6ff"Ta5d6ff::error::fdroid APK contains proprietary libraries:Tffd700${Te6edf3OFFENDERSTffd700}Ta5d6ff"
Tffa657exit T79c0ff1
Tff7b72fi
Tffa657echo Ta5d6ff"βœ… No proprietary libraries in fdroid APK"

Tffa657echo Ta5d6ff"── Step 5: Check for DEPENDENCY_INFO_BLOCK (signing block blob) ──"
T8b949e# Parse the signing block properly; naive byte scans false-positive.
T8b949e# Exit codes: 0 clean, 2 found, else parser crash.
Te6edf3rcTff7b72=T79c0ff0
python3 - Ta5d6ff"Te6edf3$APKTa5d6ff" Ta5d6ff<<'PYEOF' || rc=$?
import struct, sys

with open(sys.argv[1], "rb") as f:
data = f.read()

magic = b"APK Sig Block 42"
idx = data.rfind(magic)
if idx < 0:
sys.exit(0)

block_size = struct.unpack_from("<Q", data, idx - 8)[0]
block_start = idx + 16 - 8 - block_size
pos = int(block_start)
end = idx - 8

while pos + 12 <= end:
pair_size = struct.unpack_from("<Q", data, pos)[0]
pair_id = struct.unpack_from("<I", data, pos + 8)[0]
if pair_id == 0x504b4453:
print(f"DEPENDENCY_INFO_BLOCK found (id=0x{pair_id:08x})")
sys.exit(2)
pos += 8 + int(pair_size)

sys.exit(0)
PYEOF
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$rcTa5d6ff" -eq T79c0ff2 Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"::error::fdroid APK contains DEPENDENCY_INFO_BLOCK β€” remove with dependenciesInfo { includeInApk = false }"
Tffa657exit T79c0ff1
Tff7b72elif Tff7b72[ Ta5d6ff"Te6edf3$rcTa5d6ff" -ne T79c0ff0 Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"Ta5d6ff::error::DEPENDENCY_INFO_BLOCK check failed to parse the APK signing block (exit Te6edf3$rcTa5d6ff)Ta5d6ff"
Tffa657exit T79c0ff1
Tff7b72fi
Tffa657echo Ta5d6ff"βœ… No DEPENDENCY_INFO_BLOCK in signing block"

Tffa657echo Ta5d6ff"── Step 6: Check native libraries have debug symbols (not stripped) ──"
Te6edf3STRIPPED_LIBSTff7b72=Ta5d6ff""
Tff7b72while Te6edf3IFSTff7b72= Tffa657read -r -d Ta5d6ff'' soTb4b4b4; Tff7b72do
T8b949e# no .symtab = stripped
Tff7b72if ! readelf -S Ta5d6ff"Te6edf3$soTa5d6ff" T79c0ff2>/dev/null Tb4b4b4| grep -q Ta5d6ff"\.symtab"Tb4b4b4; Tff7b72then
Te6edf3STRIPPED_LIBSTff7b72=Ta5d6ff"Tffd700${Te6edf3STRIPPED_LIBSTffd700}Ta5d6ff Tff7b72$(basename Ta5d6ff"Te6edf3$soTa5d6ff"Tff7b72)Ta5d6ff"
Tff7b72fi
Tff7b72done < <Tff7b72(find Ta5d6ff"Te6edf3$APK_DIRTa5d6ff" -name Ta5d6ff"*.so" -print0 T79c0ff2>/dev/nullTff7b72)
T8b949e# some third-party .so arrive pre-stripped β€” warn only
Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$STRIPPED_LIBSTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"Ta5d6ff::warning::Some native libraries appear stripped (may cause NDK-version-dependent RB failures):Tffd700${Te6edf3STRIPPED_LIBSTffd700}Ta5d6ff"
Tff7b72else
Tffa657echo Ta5d6ff"βœ… Native libraries retain debug symbols"
Tff7b72fi

Tffa657echo Ta5d6ff"── Step 7: Check aboutlibraries 'generated' timestamp not in APK ──"
T8b949e# "generated" field = build-time timestamp
Te6edf3ABOUT_JSONTff7b72=Ta5d6ff""
Tff7b72if Tff7b72[ -f Ta5d6ff"Te6edf3$APK_DIRTa5d6ff/aboutlibraries.jsonTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3ABOUT_JSONTff7b72=Ta5d6ff"Te6edf3$APK_DIRTa5d6ff/aboutlibraries.jsonTa5d6ff"
Tff7b72else
Te6edf3ABOUT_JSONTff7b72=Tff7b72$(find Ta5d6ff"Te6edf3$APK_DIRTa5d6ff/resTa5d6ff" -name Ta5d6ff"*.json" -exec grep -l Ta5d6ff"aboutLibraries" Tff7b72{Tff7b72} Tffea00\; T79c0ff2>/dev/null Tb4b4b4| head -1Tff7b72)
Tff7b72fi
Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$ABOUT_JSONTa5d6ff" Tff7b72] Tff7b72&& grep -q Ta5d6ff'"generated"' Ta5d6ff"Te6edf3$ABOUT_JSONTa5d6ff"Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"::error::aboutlibraries contains 'generated' timestamp field β€” add excludeFields = listOf(\"generated\") to build config"
Tffa657exit T79c0ff1
Tff7b72fi
Tffa657echo Ta5d6ff"βœ… No 'generated' timestamp in aboutlibraries data"

Tffa657echo Ta5d6ff"── Step 8: Verify build from clean tree (version-control-info) ──"
Tff7b72if Tff7b72[ -f Ta5d6ff"Te6edf3$APK_DIRTa5d6ff/META-INF/version-control-info.textprotoTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tff7b72if grep -q Ta5d6ff"modified: true" Ta5d6ff"Te6edf3$APK_DIRTa5d6ff/META-INF/version-control-info.textprotoTa5d6ff"Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"::warning::APK built from dirty tree (version-control-info shows modified:true). Release builds must use a clean tree."
Tff7b72else
Tffa657echo Ta5d6ff"βœ… Built from clean tree"
Tff7b72fi
Tff7b72else
Tffa657echo Ta5d6ff"ℹ️ No version-control-info.textproto (AGP may not embed it for debug-signed builds)"
Tff7b72fi

Tffa657echo Ta5d6ff""
Tffa657echo Ta5d6ff"πŸŽ‰ All RB checks passed"

Served by rngit 1.5.0 - Generated in 0.05s